/**
@C++ Standard: 11
@Copyright:Copyright (c) 2019 Harold Hu. All rights reserved.
@Author: Created by Harold Hu with CLion on 2019/1/15 15:47.
@File Name: testScopeGuard.cpp
@Description: 
*/
#define TEST_SCOPEGUARD 1
#if TEST_SCOPEGUARD

#include "../../../TestFramework/HaroldDebug.h"

#if TEST_TYPE == TEST_GTEST

#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "glog/logging.h"

namespace {

#include "../../../Inc/ScopeGuard.h"
	
	struct tT
	{
		tT() : _numA(1), _numB(2), _numC(3)
		{
		}
		
		tT(const int& numA, const int& numB, const int& numC) : _numA(numA), _numB(numB), _numC(numC)
		{
		}
		
		//		tT(const tT&) = default;
		tT(const tT& other) : _numA(other._numA), _numB(other._numB), _numC(other._numC)
		{
			cout << "==============copied===============" << endl;
		}
		
		tT& operator=(const tT&) = default;
		
		bool operator==(const tT& rhs) const
		{
			if (this == &rhs)
			{
				return true;
			}
			return (_numA == rhs._numA) && (_numB == rhs._numB) && (_numC == rhs._numC);
		}
		
		friend std::ostream& operator<<(std::ostream& os, const tT& type)
		{
			os << "_numA: " << type._numA << " _numB: " << type._numB << " _numC: " << type._numC << " num: "
			   << tT::num;
			return os;
		}
		
		~tT() = default;
		
		int _numA;
		int _numB;
		int _numC;
		static int num;
		
	};
	
	int tT::num = 0;
	
	void cleanWork1(tT& testTypeOne)
	{
		cout << "=================Oops!!!====================" << endl;
		cout << __func__ << endl;
		cout << testTypeOne << endl;
		cout << "=================Oops!!!====================" << endl;
	}
	
	void cleanWork2(tT& testTypeOne, const int& num)
	{
		cout << "=================Oops!!!====================" << endl;
		cout << __func__ << endl;
		cout << testTypeOne << endl;
		cout << num << endl;
		cout << "=================Oops!!!====================" << endl;
	}
	
	void cleanWork3(tT& testTypeOne, std::string& msgReport)
	{
		cout << "=================Oops!!!====================" << endl;
		cout << __func__ << endl;
		cout << testTypeOne << endl;
		cout << msgReport << endl;
		cout << "=================Oops!!!====================" << endl;
	}
	
	struct BABA
	{
		void Happy()
		{
			cout << "I'm your Papa !!! " << endl;
		}
		
		void Lalala(int numA)
		{
			cout << "numA: " << numA << endl;
			cout << "numStatic: " << _numStatic << endl;
		}
		
		void Sad()
		{
			cout << "You are my Papa !!! " << endl;
		}
		
		static void Peace()
		{
			cout << "Who are you ??? " << endl;
		}
		
		static int _numStatic;
	};
	
	int BABA::_numStatic = 0;
	
	TEST(TestScopeGuard, Test)
	{
		cout << "\n\n";
		BABA baba;
		tT test1(4, 5, 6);
		tT test2(7, 8, 9);
		tT test3(1, 2, 3);
		tT test4(10, 10, 10);
		tT test5(20, 20, 20);
		auto cleanWorkLambda = [](tT& testTypeOne, std::string& msgReport)
		{
			cout << "=================Oops!!!====================" << endl;
			cout << testTypeOne << endl;
			cout << msgReport << endl;
			cout << "=================Oops!!!====================" << endl;
		};
		using funcType = void(tT&, const int&);
		funcType* fPtr2 = &cleanWork2;
		const int a = 555;
		std::string aa = "555~~~";
		auto GuardTestType1 = createGuard(&cleanWork1, std::ref(test1));
		GuardTestType1 = createGuard(&cleanWork1, std::ref(test1));
		auto GuardTestType2 = createGuard(&cleanWork2, std::ref(test2), std::ref(a));
//		auto GuardTestType3 = ScopeGuard<void(tT&,const int&), tT&, const int&>(cleanWork2, std::ref(test3), 3);
//		auto GuardTestType4 = ScopeGuard<decltype(cleanWork3), tT&, const std::string&>(cleanWork3, std::ref(test4),
//																						std::cref(aa));
		auto GuardTestType5 = createGuard(std::ref(cleanWorkLambda), std::ref(test5), std::ref(aa));
		auto GuardTestType6 = createGuard(fPtr2, std::ref(test5), std::cref(a));
		auto GuardTestType7 = createGuard([](tT& testTypeOne, std::string& msgReport)
										  {
											  cout << "=================Oops!!!====================" << endl;
											  cout << testTypeOne << endl;
											  cout << msgReport << endl;
											  cout << "GuardTestType7" << endl;
											  cout << "=================Oops!!!====================" << endl;
										  }, std::ref(test5), std::ref(aa));
		auto memberFuncPtr1 = &BABA::Happy;
		auto memberFuncPtr2 = &BABA::Sad;
		auto memberFuncPtr3 = &BABA::Lalala;
		auto staticMemberFuncPtr3 = &BABA::Peace;
		auto GuardTestType8 = createGuard(memberFuncPtr1, &baba);
		auto GuardTestType9 = createGuard(memberFuncPtr2, baba);
		auto GuardTestType10 = createGuard(memberFuncPtr3, baba, 1);
		auto GuardTestType11 = createGuard(staticMemberFuncPtr3);
		GuardTestType1.beSafe();
		GuardTestType2.beSafe();
//		GuardTestType3.beSafe();
//		GuardTestType4.beSafe();
		GuardTestType5.beSafe();
		GuardTestType6.beSafe();
		GuardTestType7.beSafe();
	}
}
#endif
#endif